<template>
  <div :class="prefixCls">
    <TreeSelect v-bind="getAttrs" v-model:value="state" :treeData="treeDataRef" @click="handleFetch">
      <template #[item]="data" v-for="item in Object.keys($slots)">
        <slot :name="item" v-bind="data || {}"></slot>
      </template>
      <template #notFoundContent v-if="loading">
        <span>
          <LoadingOutlined spin class="mr-1" />
          {{ t("component.form.apiSelectNotFound") }}
        </span>
      </template>
    </TreeSelect>
  </div>
</template>
<script lang="ts">
  import { defineComponent, ref, unref, computed, watch, onMounted } from "vue"
  import { TreeSelect } from "ant-design-vue"
  import { isEmpty, isFunction } from "/@/utils/is"
  import { propTypes } from "/@/utils/propTypes"
  import { listToTree } from "/@/utils/helper/treeHelper"
  import { useAttrs } from "/@/hooks/core/useAttrs"
  import { useRuleFormItem } from "/@/hooks/component/useFormItem"
  import { get, omit } from "lodash-es"
  import { LoadingOutlined } from "@ant-design/icons-vue"
  import { useI18n } from "/@/hooks/web/useI18n"
  import { TreeItem } from "/@/components/Tree"
  import { useDesign } from "/@/hooks/web/useDesign"

  export default defineComponent({
    name: "MyTreeSelect",
    components: { TreeSelect, LoadingOutlined },
    // inheritAttrs: false,
    props: {
      value: {
        type: [Array, Object, String, Number] as PropType<Array<any> | object | string | number>,
      },
      labelValue: {
        type: [Array, Object, String, Number] as PropType<Array<any> | object | string | number>,
      },
      labelInValue: propTypes.bool,
      treeData: {
        type: Array as PropType<Recordable[] | TreeItem[]>,
        default: () => [],
      },
      api: {
        type: Function as PropType<(arg?: Recordable) => Promise<Recordable[] | TreeItem[]>>,
        default: null,
      },
      params: {
        type: Object as PropType<Recordable>,
        default: () => ({}),
      },
      isDisable: {
        type: Function as PropType<(node: Recordable) => boolean>,
        default: null,
      },
      resultField: propTypes.string.def(""),
      immediate: propTypes.bool.def(false),
      // 暂时不支持
      dictType: propTypes.string,
      treeCheckable: propTypes.bool,
      treeDataSimpleMode: propTypes.bool.def(true),
      canSelectParent: propTypes.bool.def(true),

      // 后端返回的树结构
      //  id: 'id',
      //  children: 'children',
      //  pid: 'pid',
      fieldNames: propTypes.object.def({
        value: "id",
        label: "name",
        id: "id",
        name: "name",
        pid: "pid",
        children: "children",
      }),
    },
    emits: ["options-change", "change", "click"],
    setup(props, { emit }) {
      const { prefixCls } = useDesign("my-tree-select")
      const { t } = useI18n()
      const attrs = useAttrs()

      const treeDataRef = ref<Recordable[]>(props.treeData)
      const isFirstLoad = ref<Boolean>(false)
      const loading = ref<Boolean>(false)

      const getAttrs = computed(() => {
        let propsData = {
          height: 400, // 虚拟滚动
          showSearch: true,
          treeNodeFilterProp: props.fieldNames.name || "name",
          // fieldNames: {
          //   value: 'id',
          //   label: props.fieldNames.name || 'name',
          // },
          treeDataSimpleMode: false,
          dropdownStyle: { maxHeight: "300px" },
          popupClassName: "my-tree-select-popup",
          getPopupContainer: () => document.body,
          ...unref(attrs),
          ...(props as Recordable),
        }
        return omit(propsData, "treeData")
      })

      const [state] = useRuleFormItem(props)

      if (!isEmpty(props.dictCode)) {
        // const { initSelectTreeData } = useDict();
        // initSelectTreeData(treeDataRef, props.dictType, true);
      }

      watch(
        () => props.treeData,
        () => {
          treeDataRef.value = getTreeData(props.treeData)
          emit("options-change", unref(treeDataRef))
        }
      )

      watch(
        () => props.params,
        () => {
          isFirstLoad.value && fetch()
        },
        { deep: true }
      )

      watch(
        () => props.immediate,
        (v) => {
          v && !isFirstLoad.value && fetch()
        }
      )

      onMounted(async () => {
        if (props.treeData && props.treeData.length > 0) {
          treeDataRef.value = getTreeData(props.treeData)
        }
        if (props.immediate) {
          await fetch()
          isFirstLoad.value = true
        }
      })

      async function fetch() {
        const { api } = props
        if (!api || !isFunction(api)) return
        treeDataRef.value = []
        try {
          loading.value = true
          let res = await api(props.params)
          if (props.resultField) {
            res = get(res, props.resultField) || []
          }
          if (Array.isArray(res)) {
            treeDataRef.value = getTreeData(res)
          }
          emit("options-change", unref(treeDataRef))
        } catch (error) {
          console.warn(error)
        } finally {
          loading.value = false
        }
      }

      function getTreeData(treeData: Recordable[]) {
        const { fieldNames } = unref(props)
        if (props.treeDataSimpleMode) {
          const tree = listToTree(treeData, {
            id: fieldNames.id || "id",
            pid: fieldNames.pid || "pid",
            children: fieldNames.children || "children",
            callback: (parent, node) => {
              if (props.isDisable && node) {
                node.disabled = node.disabled || props.isDisable(node)
              }
              if (!props.canSelectParent && parent) {
                if (parent.children && parent.children.length > 0) {
                  parent.disabled = true
                }
              }
            },
          })
          return tree
        }
        return treeData
      }

      async function handleFetch() {
        if (!props.immediate && !unref(isFirstLoad)) {
          await fetch()
          isFirstLoad.value = true
        }
        emit("click")
      }

      return { prefixCls, t, getAttrs, state, treeDataRef, loading, handleFetch }
    },
  })
</script>
<style lang="less">
  @prefix-cls: ~"@{namespace}-dark-switch";

  .@{prefix-cls} {
    width: 100%;
    .ant-select {
      width: 100%;
    }
  }

  .ant-select-dropdown.@{prefix-cls}-popup .ant-select-tree {
    .ant-select-tree-switcher {
      &.ant-select-tree-switcher-noop {
        width: 15px;
      }
      .ant-select-tree-switcher-icon svg {
        margin-top: -3px;
      }
    }
  }
</style>
